package wkt.student;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Maps;
import lombok.Data;
import net.xnzn.framework.config.exception.BizRuntimeException;
import net.xnzn.framework.data.mybatis.Paging;
import net.xnzn.framework.id.Id;
import net.xnzn.framework.secure.filter.annotation.RequiresAuthentication;
import net.xnzn.framework.secure.filter.before.security.SmUtils;
import org.hibernate.validator.constraints.Range;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import wkt.RequireStudentLogin;
import wkt.WebUtils;
import wkt.auth.MiniAppUserController;
import wkt.basic.Basic;
import wkt.basic.BasicExamDate;
import wkt.basic.BasicExamDateMapper;
import wkt.basic.BasicMapper;
import wkt.notice.Notice;
import wkt.notice.NoticeController;
import wkt.notice.NoticeTips;
import wkt.notice.NoticeTipsController;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/student")
@Validated

public class StudentController {
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private BasicMapper basicMapper;
    @Autowired
    private BasicExamDateMapper basicExamDateMapper;
    @Autowired
    private NoticeTipsController noticeTipsController;
    @Autowired
    private NoticeController noticeController;
    @Autowired
    private MiniAppUserController miniAppUserController;

    @RequiresAuthentication
    @PostMapping("/list/{pageSize}/{pageNum}")
    public Paging<Student> list(@RequestBody Student student, @PathVariable @Range(min = 1, max = 100, message = "请输入1-100") int pageSize, @PathVariable int pageNum) {
        PageHelper.startPage(pageNum, pageSize);
        final LambdaQueryWrapper<Student> queryWrapper = Wrappers.lambdaQuery(Student.class)
                .select(Student::getId, Student::getName, Student::getMobile, Student::getAccount, Student::getExamDateId, Student::getOpenId, Student::getUsedTimeSecond,Student::isRemoveOnAnswerRight)
                .eq(Student::getState, "NORMAL")
                .orderByDesc(Student::getId);
        if (CharSequenceUtil.isNotBlank(student.getName())) queryWrapper.like(Student::getName, student.getName());
        if (CharSequenceUtil.isNotBlank(student.getMobile()))
            queryWrapper.like(Student::getMobile, student.getMobile());
        if (CharSequenceUtil.isNotBlank(student.getAccount()))
            queryWrapper.like(Student::getAccount, student.getAccount());
        if (student.getExamDateId() != null) queryWrapper.eq(Student::getExamDateId, student.getExamDateId());
        final List<Student> students = studentMapper.selectList(queryWrapper);
        if (CollUtil.isEmpty(students)) return Paging.build(students);

        final List<BasicExamDate> basicExamDates = basicExamDateMapper.selectList(Wrappers.lambdaQuery(BasicExamDate.class)
                .select(BasicExamDate::getId, BasicExamDate::getBasicId, BasicExamDate::getDate)
                .in(BasicExamDate::getId, students.stream().map(Student::getExamDateId).collect(Collectors.toSet())));
        final Map<Long, BasicExamDate> examDateId_examDate = basicExamDates.stream().collect(Collectors.toMap(BasicExamDate::getId, Function.identity(), (o, n) -> n));

        List<Basic> zhuanyes = basicMapper.selectList(Wrappers.lambdaQuery(Basic.class)
                .select(Basic::getId, Basic::getName, Basic::getCode, Basic::getType, Basic::getParentId)
                .in(Basic::getId, basicExamDates.stream().map(BasicExamDate::getBasicId).collect(Collectors.toSet())));
        final Map<Long, Basic> basicId_zhuanye = zhuanyes.stream().collect(Collectors.toMap(Basic::getId, Function.identity(), (o, n) -> n));

        List<Basic> cencis = basicMapper.selectList(Wrappers.lambdaQuery(Basic.class)
                .select(Basic::getId, Basic::getName, Basic::getCode, Basic::getType, Basic::getParentId)
                .in(Basic::getId, zhuanyes.stream().map(Basic::getParentId).collect(Collectors.toSet())));
        final Map<Long, Basic> basicId_cencis = cencis.stream().collect(Collectors.toMap(Basic::getId, Function.identity(), (o, n) -> n));
        students.forEach(student1 -> {
            student1.setExamDate(examDateId_examDate.get(student1.getExamDateId()));
            student1.setZhuanye(basicId_zhuanye.get(student1.getExamDate().getBasicId()));
            student1.setCenci(basicId_cencis.get(student1.getZhuanye().getParentId()));
        });

        return Paging.build(students);
    }

    @PostMapping("/get")
    @RequiresAuthentication
    public Student getExamDate(@RequestBody Student student) {
        return miniAppUserController.completeInfo(studentMapper.selectOne(Wrappers.lambdaQuery(Student.class)
                .select(Student::getId, Student::getName, Student::getMobile, Student::getAccount, Student::getExamDateId, Student::getOpenId, Student::getUsedTimeSecond,Student::isRemoveOnAnswerRight)
                .eq(Student::getId, student.getId())));
    }

    @PostMapping("/delete")
    @RequiresAuthentication
    public void deleteExamDate(@RequestBody Student student) {
        studentMapper.update(null, Wrappers.lambdaUpdate(Student.class)
                .eq(Student::getId, student.getId())
                .set(Student::getState, "DELETE"));
    }

    @PostMapping("/upsert")
    @RequiresAuthentication
    public void update(@RequestBody Student student) {
        final LambdaQueryWrapper<Student> queryWrapper = Wrappers.lambdaQuery(Student.class)
                .select(Student::getId, Student::getName, Student::getMobile, Student::getAccount, Student::getExamDateId, Student::getOpenId, Student::getUsedTimeSecond,Student::isRemoveOnAnswerRight).orderByDesc(Student::getId)
                .eq(Student::getAccount, student.getAccount()).eq(Student::getState, "NORMAL").last("limit 1");
        if (student.getId() != null) queryWrapper.ne(Student::getId, student.getId());

        final Student student1 = studentMapper.selectOne(queryWrapper);
        if (student1 != null) throw new BizRuntimeException("登录账号[" + student.getAccount() + "]已存在");

        if (student.getId() == null) {
            student.setId(Id.next());
            SortedMap<String, String> data = Maps.newTreeMap();
            data.put("password", student.getPassword());
            student.setPassword(SmUtils.signBySm3WithServerKey(data, "clientKey"));
            studentMapper.insert(student);
            return;
        }
        studentMapper.update(null, Wrappers.lambdaUpdate(Student.class)
                .eq(Student::getId, student.getId())
                .set(Student::getName, student.getName())
                .set(Student::getMobile, student.getMobile())
                .set(Student::getAccount, student.getAccount())
                .set(Student::getExamDateId, student.getExamDateId())
        );
    }

    @PostMapping("/reset-password")
    @RequiresAuthentication
    public void resetPassword(@RequestBody Student student) {
        SortedMap<String, String> data = Maps.newTreeMap();
        data.put("password", student.getPassword());
        student.setPassword(SmUtils.signBySm3WithServerKey(data, "clientKey"));
        studentMapper.update(null, Wrappers.lambdaUpdate(Student.class)
                .eq(Student::getId, student.getId())
                .set(Student::getPassword, student.getPassword())
        );
    }

    @PostMapping("/increase-used-time")
    public void increaseUsedTime(@RequestBody Student student) {
        if (WebUtils.studentId() == null) return;
        studentMapper.increaseUsedTime(WebUtils.studentId(), student.getUsedTimeSecond());
    }

    @PostMapping("/home")
    public MiniHome miniHome() {
        MiniHome miniHome = new MiniHome();
        miniHome.setNoticeTips(noticeTipsController.get());
        miniHome.setNotice(noticeController.list(new Notice(), 100, 1).getData());
        return miniHome;
    }

    @PostMapping("/change-remove-on-answer-right")
    @RequireStudentLogin
    public void changeRemoveOnAnswerRight(@RequestBody Student student) {
        studentMapper.update(null, Wrappers.lambdaUpdate(Student.class).eq(Student::getId, WebUtils.studentId()).set(Student::isRemoveOnAnswerRight, student.isRemoveOnAnswerRight()));
    }

    @Data
    public static class MiniHome {
        private NoticeTips noticeTips;
        private Collection<Notice> notice;
    }
}

